﻿using System;
using System.Collections.Generic;
using System.Threading;
using NUnit.Framework;

namespace PoolKit.Tests
{
    [TestFixture]
    class WaitableTests
    {
        [Test]
        public void MakeSureYouCannotInitializeWaitableValueMoreThanOnce()
        {
            var waitable = new Waitable<string>();

            waitable.Initialize(String.Empty);

            Assert.Throws<InvalidOperationException>(
                delegate()
                    {
                        waitable.Initialize(String.Empty);
                    });
        }

        [Test]
        public void MakeSureYouCannotInitializeWaitableValueWithNull()
        {
            var waitable = new Waitable<string>();

            Assert.Throws<ArgumentNullException>(
                delegate()
                {
                    waitable.Initialize(null);
                });
        }

        [Test]
        [Timeout(5000)]
        public void MakeSureWaitIsUnblockedByCallingInitializeSingleThreadedTest()
        {
            var waitable = new Waitable<string>();

            waitable.Initialize("hey");

            waitable.WaitUntilValueIsSet();
        }

        [Test]
        [Timeout(5000)]
        public void MakeSureWaitersAreUnblockedByCallingInitializeMultithreadedTest()
        {
            var waitable = new Waitable<string>();

            var initializingThread =
                new Thread(
                    delegate()
                    {
                        waitable.Initialize("hey");
                    });

            var waitingThreads = new List<Thread>();

            for (int i = 0; i < 100; i++)
            {
                var newThread =
                    new Thread(delegate()
                                   {
                                       waitable.WaitUntilValueIsSet();
                                   });

                newThread.Start();

                waitingThreads.Add(newThread);

                if (i == 50)
                {
                    initializingThread.Start();
                }
            }

            foreach (Thread waitingThread in waitingThreads)
            {
                waitingThread.Join();
            }
        }

        [Test]
        public void MakeSureWaitReturnsSameValueThatWasSetInInitialize()
        {
            var waitable = new Waitable<string>();

            const string heyYou = "hey";

            waitable.Initialize(heyYou);

            Assert.AreSame(heyYou, waitable.WaitUntilValueIsSet());
        }
    }
}